﻿using HalconDotNet;
using MVSDK;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using VisionRoc.Tool;
using CameraHandle = System.Int32;

namespace VisionRoc.Core
{

    public enum emCameraGPIOMode
    {
        IOMODE_TRIG_INPUT = 0,      //触发输入
        IOMODE_STROBE_OUTPUT,       //闪光灯输出
        IOMODE_GP_INPUT,            //通用型输入
        IOMODE_GP_OUTPUT,           //通用型输出
        IOMODE_PWM_OUTPUT,          //PWM型输出
    }
    public class MindVision
    {
        protected IntPtr m_Grabber = IntPtr.Zero;
        protected CameraHandle m_hCamera = 0;
        protected tSdkCameraDevInfo m_DevInfo;
        protected pfnCameraGrabberFrameCallback m_FrameCallback;
        protected pfnCameraGrabberSaveImageComplete m_SaveImageComplete;

        public delegate void delegateProcessHImage(Boolean isColor, int width, int height, IntPtr frameAddress);
        public event delegateProcessHImage eventProcessImage;

        public MindCamera My_Camera;

        public HObject Image;
        public MindVision(string path, string CameraName, HWindowControl Hwindow, out int IniCCDInfo)
        {
            HOperatorSet.GenEmptyObj(out Image);
            My_Camera = new MindCamera(path);
            IniCCDInfo = IniCamer(My_Camera.CAMERA_INIT_INFO);
            if (m_BInitCam == true)
            {
                Set_Exposure(My_Camera.Exposure);
                Set_Gain(My_Camera.Gain);
                Global.AddLogInfoEvent(LogLevel.OK, $"相机序列号：{m_strSN} 设备初始化成功。曝光：{My_Camera.Exposure.ToString()}。增益：{My_Camera.Gain.ToString()}。设置成功");
            }
            InitCamInfo(IniCCDInfo, CameraName);//显示CCD1 初始化信息
            HalconWindow(Hwindow);
        }

        /// <summary>
        /// 相机序列号
        /// </summary>
        public string m_strSN = string.Empty;

        /// <summary>
        /// 相机标志位
        /// </summary>
        public bool m_BInitCam = false;

        object o = new object();

        object o1 = new object();

        object LockImage = new object();

        public int IndexP;//读取图片计数

        /// <summary>
        /// 窗体显示图像第几张
        /// </summary>
        public long Index;

        /// <summary>
        /// 1为触发
        /// </summary>
        public int Photo;


        /// <summary>
        /// 根据序列号初始化相机
        /// </summary>
        /// <param name="SN">序列号</param>
        /// <returns></returns>
        public int IniCamer(string SN)
        {
            try
            {
                if (My_Camera.CAMERA_STATE != 3)
                {
                    return -1;
                }

                m_FrameCallback = new pfnCameraGrabberFrameCallback(CameraGrabberFrameCallback);
                m_SaveImageComplete = new pfnCameraGrabberSaveImageComplete(CameraGrabberSaveImageComplete);
                tSdkCameraDevInfo[] DevList;
                MvApi.CameraEnumerateDevice(out DevList);
                int NumDev = (DevList != null ? DevList.Length : 0);
                if (NumDev < 1)
                {
                    return -2;
                }
                else
                {

                    for (int i = 0; i < DevList.Length; i++)
                    {
                        byte[] sn = DevList[i].acSn;
                        m_strSN = Encoding.UTF8.GetString(sn);
                        m_strSN = m_strSN.Substring(0, 12);

                        if (SN == m_strSN)
                        {
                            CameraSdkStatus result = MvApi.CameraGrabber_Create(out m_Grabber, ref DevList[i]);
                            if (result == CameraSdkStatus.CAMERA_STATUS_SUCCESS)
                            {
                                MvApi.CameraGrabber_GetCameraDevInfo(m_Grabber, out m_DevInfo);
                                MvApi.CameraGrabber_GetCameraHandle(m_Grabber, out m_hCamera);
                                MvApi.CameraGrabber_SetRGBCallback(m_Grabber, m_FrameCallback, IntPtr.Zero);
                                MvApi.CameraGrabber_SetSaveImageCompleteCallback(m_Grabber, m_SaveImageComplete, IntPtr.Zero);
                                // 黑白相机设置ISP输出灰度图像
                                // 彩色相机ISP默认会输出BGR24图像
                                tSdkCameraCapbility cap;
                                MvApi.CameraGetCapability(m_hCamera, out cap);
                                if (cap.sIspCapacity.bMonoSensor != 0)
                                {
                                    MvApi.CameraSetIspOutFormat(m_hCamera, (uint)MVSDK.emImageFormat.CAMERA_MEDIA_TYPE_MONO8);
                                }
                                MvApi.CameraGrabber_StartLive(m_Grabber);
                                MvApi.CameraGrabber_StopLive(m_Grabber);
                                m_BInitCam = true;

                                if (My_Camera.TRIGGER_MODEL == 1)
                                {
                                    MvApi.CameraSetStrobeMode(m_hCamera, 1);
                                    MvApi.CameraSetOutPutIOMode(m_hCamera, 0, (int)emCameraGPIOMode.IOMODE_STROBE_OUTPUT);
                                    MvApi.CameraSetStrobePolarity(m_hCamera, 0);
                                    MvApi.CameraSetExtTrigSignalType(m_hCamera, 0);
                                    MvApi.CameraSetTriggerMode(m_hCamera, 2);
                                    MvApi.CameraPause(m_hCamera);
                                    MvApi.CameraGrabber_StartLive(m_Grabber);
                                }

                                if (My_Camera.TRIGGER_MODEL == 2)
                                {
                                    MvApi.CameraSetTriggerMode(m_hCamera, 1);
                                }

                                eventProcessImage += ImageCallbackHandle;
                                return 0;
                            }
                            else
                            {
                                m_BInitCam = false;
                                return -7;
                            }
                        }
                    }
                    m_BInitCam = false;
                    return -3;
                }
            }
            catch (Exception ex)
            {
                m_BInitCam = false;
                Global.AddLogInfoEvent(LogLevel.Error, $"序列号：{SN}，相机初始化异常。失败信息已写入文本");
                TxtAPI.WriteLogTxt($"序列号：{SN}，相机初始化异常。失败信息：{ex.ToString()}");
                return -4;
            }
        }

        /// <summary>
        /// 设置曝光
        /// </summary>
        /// <param name="iShutter"></param>
        public void Set_Exposure(double iShutter)
        {
            MvApi.CameraSetAeState(m_hCamera, 0);//0为手动曝光模式,1为自动曝光模式                  
            MvApi.CameraSetExposureTime(m_hCamera, iShutter);
        }

        /// <summary>
        /// 设置增益
        /// </summary>
        /// <param name="iGain"></param>
        public void Set_Gain(int iGain)
        {
            MvApi.CameraSetAeState(m_hCamera, 0);
            MvApi.CameraSetAnalogGain(m_hCamera, iGain);
        }

        /// <summary>
        /// 窗体控件
        /// </summary>
        HWindowControl MyHwindow;

        /// <summary>
        /// 返回窗体控件
        /// </summary>
        /// <param name="hSmart"></param>
        /// <returns></returns>
        public void HalconWindow(HWindowControl Hwindow)
        {
            MyHwindow = Hwindow;
        }

        /// <summary>
        /// 触发源设置
        /// </summary>
        public string TriggerMode
        {
            get
            {
                int piModelsel = -1;
                MvApi.CameraGetTriggerMode(m_hCamera, ref piModelsel);
                if (piModelsel == 1 || piModelsel == 2)
                {
                    return "On";//1软触发模式，2硬触发模式都返回“On”,表示触发打开
                }
                return "Off";  //0连续模式，返回"Off",表示触发关闭            
            }
            set
            {
                int iModeSel = 0;

                if (value == "On")
                {
                    iModeSel = 1; //触发打开默认设置为软触发模式
                }
                if (value == "Off")
                {
                    iModeSel = 0;//触发关闭默认设置为连续模式
                }
                if (value == "Line1")
                {
                    iModeSel = 2;//硬触发模式
                }
                MvApi.CameraSetTriggerMode(m_hCamera, iModeSel);
            }
        }

        /// <summary>
        /// 发送软触发指令
        /// </summary>
        /// <returns></returns>
        public void Trigger()
        {
            try
            {
                if (My_Camera.CAMERA_STATE == 3)
                {
                    if (My_Camera.TRIGGER_MODEL == 1 || My_Camera.TRIGGER_MODEL == 2)
                    {
                        if (!m_BInitCam)
                        {
                            Global.AddLogInfoEvent(LogLevel.Error, "相机未初始化!");
                            return;
                        }
                        if (m_Grabber != IntPtr.Zero)
                            MvApi.CameraGrabber_StartLive(m_Grabber);
                        MvApi.CameraSoftTrigger(m_hCamera);
                        return;
                    }
                    Global.AddLogInfoEvent(LogLevel.Error, "连续触发模式下不可以单帧采集!");
                }
                else
                {
                    lock (o1)
                    {
                        OffLine_ReadImage();
                    }
                }
            }
            catch
            {
                Global.AddLogInfoEvent(LogLevel.Error, "相机触发异常!");
            }
        }

        /// <summary>
        /// 发送软触发指令
        /// </summary>
        /// <returns></returns>
        public void Trigger(HWindowControl hSmart)
        {
            try
            {
                MyHwindow = hSmart;
                if (My_Camera.CAMERA_STATE == 3)
                {
                    if (!m_BInitCam)
                    {
                        Global.AddLogInfoEvent(LogLevel.Error, "相机未初始化!");
                        return;
                    }
                    if (m_Grabber != IntPtr.Zero)
                        MvApi.CameraGrabber_StartLive(m_Grabber);
                    MvApi.CameraSoftTrigger(m_hCamera);
                }
                else
                {
                    lock (o1)
                    {
                        OffLine_ReadImage();
                    }
                }
            }
            catch
            {
                Global.AddLogInfoEvent(LogLevel.Error, "相机触发异常!");
            }
        }

        /// <summary>
        /// 连续触发 
        /// </summary>
        /// <param name="on"> True 为开始连续采集  False 关闭连续采集</param>
        public void Continuous(bool on)
        {
            try
            {
                if (on)
                {
                    if (m_Grabber != IntPtr.Zero)
                        MvApi.CameraGrabber_StartLive(m_Grabber);
                }
                else
                {
                    if (m_Grabber != IntPtr.Zero)
                        MvApi.CameraGrabber_StopLive(m_Grabber);
                }
                return;
            }
            catch
            {
                return;
            }
        }

        /// <summary>
        /// 离线读取图像
        /// </summary>
        public void OffLine_ReadImage()
        {
            try
            {
                //lock (o1)
                //{
                if (My_Camera.CAMERA_STATE != 3)
                {
                    if (My_Camera.CAMERA_STATE == 1)
                    {
                        lock (LockImage)
                        {
                            Image.Dispose();
                            HOperatorSet.ReadImage(out Image, My_Camera.OFFLINE_IMAGE_PATH);
                        }

                    }
                    else if (My_Camera.CAMERA_STATE == 2)
                    {
                        if (My_Camera.OFFLINE_IMAGE_FILE_PATH != "" && My_Camera.hv_ImageFiles != null)
                        {
                            if (My_Camera.hv_ImageFiles.TupleLength() > 0)
                            {
                                lock (LockImage)
                                {
                                    HOperatorSet.ReadImage(out Image, My_Camera.hv_ImageFiles.TupleSelect(IndexP++));
                                    if (IndexP >= My_Camera.hv_ImageFiles.TupleLength() - 1)
                                    {
                                        IndexP = 0;
                                    }

                                }
                            }
                        }
                    }

                    if (Image == null && !MyHOperatorSet.ObjectValided(Image))
                    {
                        MyHOperatorSet.DispMeassge(MyHwindow.HalconWindow, "无图像", "window", 10, 10, 20, "red");
                        return;
                    }

                    Index++;
                    // 清除窗口
                    MyHwindow.HalconWindow.ClearWindow();
                    HTuple Width = new HTuple(), Height = new HTuple();
                    Width.Dispose(); Height.Dispose();
                    HOperatorSet.GetImageSize(Image, out Width, out Height);
                    MyHOperatorSet.SetHWindowPart(ref MyHwindow, Width, Height);
                    Image.DispObj(MyHwindow.HalconWindow);




                    MyHOperatorSet.DispMeassge(MyHwindow.HalconWindow, "图片第" + Index.ToString() + "张", "window", 10, 10, 20, "green");
                    if (Global.RunState == 1)
                    {
                        Photo = 1;
                    }
                }
                else
                {

                }
                //}
            }
            catch { }


        }


        /// <summary>
        /// 实时检测相机状态
        /// </summary>
        /// <returns></returns>
        public bool CameraState()
        {
            CameraSdkStatus result = MvApi.CameraConnectTest(m_hCamera);
            if (result == CameraSdkStatus.CAMERA_STATUS_SUCCESS) //函数返回值==CAMERA_STATUS_SUCCESS  表示相机在线 否则为掉线
            {
                return true;
            }
            else
            {
                return false;
            }

        }


        /// <summary>
        /// 关闭相机
        /// </summary>
        /// <returns></returns>
        public bool CloseCamer()
        {
            MvApi.CameraGrabber_Destroy(m_Grabber);
            return true;
        }

        /// <summary>
        /// 相机回调采集图像
        /// </summary>
        /// <param name="isColor"></param>
        /// <param name="width"></param>
        /// <param name="height"></param>
        /// <param name="frameAddress"></param>
        private void ImageCallbackHandle(bool isColor, int width, int height, IntPtr frameAddress)
        {
            try
            {
                lock (o)
                {

                    if (isColor == false)
                    {
                        Image.Dispose();
                        HOperatorSet.GenImage1(out Image, "byte", (HTuple)width, (HTuple)height, (HTuple)frameAddress);//黑白
                    }
                    else
                    {
                        Image.Dispose();
                        HOperatorSet.GenImageInterleaved(out Image, frameAddress, "bgr", (HTuple)width, (HTuple)height, -1,
                            "byte", (HTuple)width, (HTuple)height, 0, 0, -1, 0);//彩色
                    }
                    HOperatorSet.MirrorImage(Image, out Image, "row");

                    if (Image == null && !MyHOperatorSet.ObjectValided(Image))
                    {
                        MyHOperatorSet.DispMeassge(MyHwindow.HalconWindow, "无图像", "window", 10, 10, 20, "red");
                        return;
                    }

                    Index++;
                    //清除窗口
                    MyHwindow.HalconWindow.ClearWindow();
                    HTuple Width = new HTuple(), Height = new HTuple();
                    Width.Dispose(); Height.Dispose();
                    HOperatorSet.GetImageSize(Image, out Width, out Height);
                    MyHOperatorSet.SetHWindowPart(ref MyHwindow, Width, Height);
                    Image.DispObj(MyHwindow.HalconWindow);



                    MyHOperatorSet.DispMeassge(MyHwindow.HalconWindow, "第" + Index.ToString() + "张图像", "window", 10, 10, 20, "green");
                    if (Global.RunState == 1)
                    {
                        Photo = 1;
                    }
                }
            }
            catch
            {

            }
        }

        /// <summary>
        /// 相机初始化信息
        /// </summary>
        /// <param name="X"></param>
        /// <param name="CCD"></param>
        public void InitCamInfo(int X, string CCD)
        {
            switch (X)
            {
                case -1:

                    Global.AddLogInfoEvent(LogLevel.Info, $"【{CCD}】 相机离线模式！");
                    break;
                case -2:
                    Global.AddLogInfoEvent(LogLevel.Error, $"【{CCD}】 未找到相机！");
                    break;
                case -3:
                    Global.AddLogInfoEvent(LogLevel.Error, $"【{CCD}】 没有找该序列号相机");
                    break;
                case -4:
                    Global.AddLogInfoEvent(LogLevel.Error, $"【{CCD}】 相机初始化异常");
                    break;
                case -7:
                    Global.AddLogInfoEvent(LogLevel.Error, $"【{CCD}】 相机打开失败！");
                    break;
                case 0:
                    Global.AddLogInfoEvent(LogLevel.OK, $"【相机序列号为:{m_strSN}】 初始化成功！");
                    break;
            }
        }

        private void CameraGrabberFrameCallback(
 IntPtr Grabber,
 IntPtr pFrameBuffer,
 ref tSdkFrameHead pFrameHead,
 IntPtr Context)
        {
            // 数据处理回调

            // 由于黑白相机在相机打开后设置了ISP输出灰度图像
            // 因此此处pFrameBuffer=8位灰度数据
            // 否则会和彩色相机一样输出BGR24数据

            // 彩色相机ISP默认会输出BGR24图像
            // pFrameBuffer=BGR24数据
            int w = pFrameHead.iWidth;
            int h = pFrameHead.iHeight;


            try
            {


                if (pFrameHead.uiMediaType == (uint)MVSDK.emImageFormat.CAMERA_MEDIA_TYPE_MONO8)
                {
                    eventProcessImage(false, w, h, pFrameBuffer);
                    //  HOperatorSet.GenImage1(out Image, "byte", w, h, pFrameBuffer);
                }
                else if (pFrameHead.uiMediaType == (uint)MVSDK.emImageFormat.CAMERA_MEDIA_TYPE_BGR8)
                {
                    eventProcessImage(true, w, h, pFrameBuffer);

                }
                else
                {
                    //throw new HalconException("Image format is not supported!!");
                }
            }
            catch
            {
            }
            finally
            {

            }
        }

        private void CameraGrabberSaveImageComplete(
            IntPtr Grabber,
            IntPtr Image,	// 需要调用CameraImage_Destroy释放
            CameraSdkStatus Status,
            IntPtr Context)
        {
            if (Image != IntPtr.Zero)
            {
                //string filename = System.IO.Path.Combine(
                //        AppDomain.CurrentDomain.BaseDirectory.ToString(),
                //        string.Format("{0}.bmp", System.Environment.TickCount));

                //MvApi.CameraImage_SaveAsBmp(Image, filename);

                ////MessageBox.Show(filename);
            }

            MvApi.CameraImage_Destroy(Image);
        }

        ~MindVision()
        {
            CloseCamer();
        }

    }
}
